<!doctype HTML public "-//W3C//DTD HTML 4.0 Frameset//EN">
<html>
<title>Bloomberg Development Environment</title>
<html>
<pre>
// Copyright 2014-2023 Bloomberg Finance L.P.
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// bmqa_session.h                                                     -*-C++-*-
#ifndef INCLUDED_BMQA_SESSION
#define INCLUDED_BMQA_SESSION

//@PURPOSE: Provide access to the BlazingMQ broker.
//
//@CLASSES:
//  bmqa::SessionEventHandler: interface for receiving events asynchronously.
//  bmqa::Session            : mechanism for access to the BlazingMQ broker.
//
//@DESCRIPTION: This component provides a mechanism, &#39;bmqa::Session&#39;, that
// provides access to a message queue broker and an interface,
// &#39;bmqa::SessionEventHandler&#39; for asynchronous notification of events.  The
// broker manages named, persistent queues of messages.  This broker allows a
// client to open queues, post messages to them, or retrieve messages from
// them.  All of these operations take place within the context of the session
// opened by the client application.
//
// Messages received from a broker are communicated to the application by the
// session associated with that broker in the form of events (see
// &#39;bmqa_event&#39;).  Events can be of two different types: (1) Messages and
// message status events (&#39;bmqa::MessageEvent&#39;), or (2) Session or queue
// status events (&#39;bmqa::SessionEvent&#39;).
//
// A &#39;Session&#39; can dispatch events to the application in either a synchronous
// or asynchronous mode.  In synchronous mode, the application must call the
// &#39;nextEvent&#39; method in order to obtain events from the &#39;Session&#39;.  In
// asynchronous mode, the application must supply a concrete
// &#39;SessionEventHandler&#39; object at construction time.  The concrete
// &#39;SessionEventHandler&#39; provided by the application must implement the
// &#39;onSessionEvent&#39; and &#39;onMessageEvent&#39; methods, which will be called by the
// &#39;Session&#39; every time a session event or a message event is received.  Note
// that by default, a session created in asynchronous mode creates only one
// internal thread to dispatch events, but a different value for number of
// threads can be specified in &#39;bmqt::SessionOptions&#39;.
//
// A &#39;Session&#39; is created either in synchronous or in asynchronous mode, and it
// will remain in that mode until destruction.  Allowing a mix between
// synchronous or asynchronous would make the SDK complicated.  The only
// exceptions are the &quot;start&quot; and &quot;open&quot; operations that must be available in
// synchronous or asynchronous version for the convenience of the programmer.
//
// By default a &#39;Session&#39; connects to the local broker, which in turn may
// connect to a remote cluster based on configuration.
//
// After a &#39;bmqa::Session&#39; is started, the application has to open one or
// several queues in read and/or write mode.
//
///Disclaimer
///----------
// A &#39;Session&#39; object is a heavy object representing the negotiated TCP session
// with the broker, and the entire associated state (opened queues, statistics,
// ...).  Therefore, sessions should be always reused if possible, preferably
// with only *one* session per lifetime of a component/library/task.
// Note that at the time of this writing multiplexing of different logical
// sessions over the same physical connection is not supported, so in certain
// circumstances reuse of the same session across the whole of a single
// application will not be possible. For example, if an application uses two
// unrelated libraries both of which use BlazingMQ under the hood, they won&#39;t
// be able to share a session as it stands.
// An example of an extreme inefficiency and an abuse of resources is to
// create a session ad-hoc every time a message needs to be posted by the same
// component.
//
///Thread-safety
///-------------
// This session object is *thread* *enabled*, meaning that two threads can
// safely call any methods on the *same* *instance* without external
// synchronization.
//
///Connecting to the Broker
///------------------------
// A &#39;Session&#39; establishes a communication with a broker service using TCP/IP.
// Each &#39;Session&#39; object must be constructed with a &#39;bmqa::SessionOptions&#39;
// object, which provides the necessary information to connect to the broker.
// In particular, the &#39;SessionOptions&#39; object must specify the IP address and
// port needed to connect to the broker.  The &#39;SessionOptions&#39; object may also
// provide extra parameters for tuning the TCP connection behavior (see
// &#39;bmqa_sessionoptions&#39; for details).
//
// Note that in most cases the user does not need to explicitly construct a
// &#39;SessionOptions&#39; object: the default constructor for &#39;SessionOptions&#39;
// creates an instance that will connect to the broker service on the local
// machine using the standard port.
//
// Some options can also be provided using environment variables.
//: o !BMQ_BROKER_URI!: Corresponds to &#39;SessionOptions::brokerUri&#39;.
//:   If this environment variable is set, its value will override the one
//:   specified in the &#39;SessionOptions&#39;.
//
// A &#39;Session&#39; object is created in an unconnected state.  The &#39;start&#39; or
// &#39;startAsync&#39; method must be called to connect to the broker.  Note that
// &#39;start&#39; method is blocking, and returns either after connection to broker
// has been established (success), or after specified timeout (failure).
// &#39;startAsync&#39; method, as the name suggests, connects to the broker
// asynchronously (i.e., it returns immediately), and the result of the
// operation is notified via &#39;bmqt::SessionEventType::CONNECTED&#39; session event.
//
// When the &#39;Session&#39; is no longer needed, the application should call the
// &#39;stop&#39; (blocking) or &#39;stopAsync&#39; (non-blocking) method to shut down the
// &#39;Session&#39; and disconnect from the broker.  Note that destroying a Session
// automatically stops it.  The session can be restarted with a call to &#39;start&#39;
// or &#39;startAsync&#39; once it has been fully stopped.
//
///Connection loss and reconnection
///--------------------------------
// If the connection between the application and the broker is lost, the
// &#39;Session&#39; will automatically try to reconnect periodically.  The &#39;Session&#39;
// will also notify the application of the event of losing the connection via
// &#39;bmqt::SessionEventType::CONNECTION_LOST&#39; session event.
//
// Once the connection has been re-established with the broker (as a result of
// one of the periodic reconnection attempts), the &#39;Session&#39; will notify the
// application via &#39;bmqt::SessionEventType::RECONNECTED&#39; session event.  After
// the connection re-establishment, the &#39;Session&#39; will attempt to reopen the
// queues that were in &#39;OPEN&#39; state prior to connection loss.  The &#39;Session&#39;
// will notify the application of the result of reopen operation via
// &#39;bmqt::SessionEventType::QUEUE_REOPEN_RESULT&#39; for each queue.  Note that a
// reopen operation on a queue may fail (due to broker issue, machine issue,
// etc), so the application must keep track on these session events, and stop
// posting on a queue that failed to reopen.
//
// After all reopen operations are complete and application has been notified
// with all &#39;bmqt::SessionEventType::QUEUE_REOPEN_RESULT&#39; events, the &#39;Session&#39;
// delivers a &#39;bmqt::SessionEventType::STATE_RESTORED&#39; session event to the
// application.
//
///Example 1
///- - - - -
// The following example illustrates how to create a &#39;Session&#39; in synchronous
// mode, start it, and stop it.
//..
//  void runSession()
//  {
//      bmqt::SessionOptions options;
//      options.setBrokerUri(&quot;tcp://localhost:30114&quot;);
//
//      bmqa::Session session(options);
//      int res = session.start();
//      if (0 != res) {
//          bsl::cout &lt;&lt; &quot;Failed to start session (&quot; &lt;&lt; res &lt;&lt; &quot;)&quot;
//                    &lt;&lt; bsl::endl;
//          return;
//      }
//      bsl::cout &lt;&lt; &quot;Session started.&quot; &lt;&lt; bsl::endl;
//
//      // Open queue in READ or WRITE or READ/WRITE mode, and receive or
//      // post messages, etc.
//      // ...
//
//      session.stop();
//  }
//..
// This example can be simplified because the constructor for &#39;Session&#39; uses a
// default &#39;SessionOptions&#39; object that will connect to the local broker
// service.  The example may be rewritten as follow:
//..
//  void runSession()
//  {
//      bmqa::Session session;     // using default &#39;SessionOptions&#39;
//      int res = session.start();
//      if (0 != res) {
//          bsl::cout &lt;&lt; &quot;Failed to start session (&quot; &lt;&lt; res &lt;&lt; &quot;)&quot;
//                    &lt;&lt; bsl::endl;
//          return;
//      }
//      bsl::cout &lt;&lt; &quot;Session started.&quot; &lt;&lt; bsl::endl;
//
//      // Open queue in READ or WRITE or READ/WRITE mode, and receive or
//      // post messages, etc.
//      // ...
//
//      session.stop();
//  }
//..
//
///Processing session events - synchronous mode
///--------------------------------------------
// If the &#39;Session&#39; is created in synchronous mode, the application needs to
// call the &#39;nextEvent&#39; method on a regular basis in order to receive events.
// This method takes an optional wait timeout as a parameter, and it will
// return the next available &#39;Event&#39; from the session&#39;s internal event queue or
// it will block the calling thread execution until new &#39;Event&#39; arrives or
// until the specified timeout expires.  It is safe to call the &#39;nextEvent&#39;
// method from different threads simultaneously: the &#39;Session&#39; class provides
// proper synchronization logic to protect the internal event queue from
// corruption in this scenario.
//
///Example 2
///- - - - -
// The following example demonstrates how to write a function that queries and
// processes events synchronously.  In this example the switch form checks the
// type of the &#39;Event&#39; and performs the necessary actions.
//
// We first define two functions to process &#39;SessionEvent&#39; and &#39;MessageEvent&#39;.
// These functions return &#39;true&#39; if we should keep processing events and
// &#39;false&#39; otherwise (i.e., no more events are expected from the &#39;Session&#39;).
//..
//  bool processSessionEvent(const bmqa::SessionEvent&amp; event)
//  {
//      bool result = true;
//      switch (event.type()) {
//
//        case bmqt::SessionEventType::e_CONNECTED:
//          // The connection to the broker is established (as a result
//          // of a call to the &#39;start&#39; method).
//          openQueues();
//          startPostingToQueues();
//          break;
//
//        case bmqt::SessionEventType::e_DISCONNECTED:
//          // The connection to the broker is terminated (as a result
//          // of a call to the &#39;stop&#39; method).
//          result = false;
//          break;
//
//        case bmqt::SessionEventType::e_CONNECTION_LOST:
//          // The connection to the broker dropped. Stop posting to the queue.
//          stopPostingToQueues();
//          break;
//
//        case bmqt::SessionEventType::e_STATE_RESTORED:
//          // The connection to the broker has been restored (i.e., all queues
//          // have been re-opened. Resume posting to the queue.
//          resumePostingToQueues();
//          break;
//
//        case bmqt::SessionEventType::e_CONNECTION_TIMEOUT:
//          // The connection to the broker has timed out.
//          result = false;
//          break;
//
//        case bmqt::SessionEventType::e_ERROR:
//          // Internal error
//          bsl::cout &lt;&lt; &quot;Unexpected session error: &quot;
//                    &lt;&lt; event.errorDescription() &lt;&lt; bsl::endl;
//          break;
//
//      } // end switch
//
//      return result;
//  }
//
//  bool processMessageEvent(const bmqa::MessageEvent&amp; event)
//  {
//      bool result = true;
//      switch (event.type()) {
//
//        case bmqt::MessageEventType::e_PUSH: {
//          // Received a &#39;PUSH&#39; event from the broker.
//          bmqa::MessageIterator msgIter = event.messageIterator();
//          while (msgIter.nextMessage()) {
//              const bmqa::Message&amp; msg = msgIter.message();
//              // Process &#39;PUSH&#39; msg here (omitted for brevity)
//              // ...
//          }
//      } break;
//
//        case bmqt::MessageEventType::e_ACK: {
//          // Received an &#39;ACK&#39; event from the broker.
//          bmqa::MessageIterator msgIter = event.messageIterator();
//          while (msgIter.nextMessage()) {
//              const bmqa::Message&amp; msg = msgIter.message();
//              // Process &#39;ACK&#39; msg here (omitted for brevity)
//              // ...
//          }
//      } break;
//
//      } // end switch
//
//      return result;
//  }
//..
//
// Next, we define a function that handles events synchronously using the
// &#39;processSessionEvent&#39; and &#39;processMessageEvent&#39; functions.
//..
//  void handleEventsSynchronously(bmqa::Session *startedSession)
//  {
//      bool more = true;
//      while (more) {
//          bmqa::Event event =
//                  startedSession-&gt;nextEvent(bsls::TimeInterval(2.0));
//          if (event.isSessionEvent()) {
//              more = processSessionEvent(event.sessionEvent());
//          }
//          else {
//              more = processMessageEvent(event.messageEvent());
//          }
//      }
//  }
//..
//
///Processing session events - asynchronous mode
///---------------------------------------------
// If application wishes to use &#39;Session&#39; in asynchronous mode, it must pass a
// managed pointer to an event handler implementing the &#39;SessionEventHandler&#39;.
// In this case, when &#39;Session&#39; is started, a thread pool owned by the
// &#39;Session&#39; is also started for processing events asynchronously.  The
// &#39;Session&#39; will call event handler&#39;s &#39;onSessionEvent&#39; or &#39;onMessageEvent&#39;
// method every time a session event or a message event is available.
//
// Note that after the &#39;Session&#39; is associated with some event handler, this
// association cannot be changed or canceled.  The event handler will be used
// for processing events until the &#39;Session&#39; object is destroyed.
//
///Example 3
///- - - - -
// The following example demonstrates how to implement an event handler and how
// to make the &#39;Session&#39; use an instance of this event handler for processing
// events.
//
// First, we define a concrete implementation of &#39;SessionEventHandler&#39;.
//
//..
//  class MyHandler: public bmqa::SessionEventHandler {
//  public:
//      MyHandler() { }
//      virtual ~MyHandler() { }
//      virtual void onSessionEvent(const bmqa::SessionEvent&amp; event);
//      virtual void onMessageEvent(const bmqa::MessageEvent&amp; event);
//  };
//
//  void MyHandler::onSessionEvent(const bmqa::SessionEvent&amp; event)
//  {
//      // The implementation is similar to our &#39;processSessionEvent&#39; function
//      // defined in the previous example.
//      processSessionEvent(event);
//  }
//
//  void MyHandler::onMessageEvent(const bmqa::MessageEvent&amp; event)
//  {
//      // The implementation is similar to our &#39;processMessageEvent&#39; function
//      // defined in the previous example.
//      processMessageEvent(event);
//  }
//..
// Next, we define a function that creates a &#39;Session&#39; using our implementation
// of &#39;SessionEventHandler&#39;.
//..
//  void runAsyncSession()
//  {
//      bslma::ManagedPtr&lt;SessionEventHandler&gt; handlerMp(new MyHandler());
//
//      bmqa::Session session(handlerMp);   // using default &#39;SessionOptions&#39;
//      int res = session.start();
//      if (0 != res) {
//          bsl::cout &lt;&lt; &quot;Failed to start session (&quot; &lt;&lt; res &lt;&lt; &quot;)&quot;
//                    &lt;&lt; bsl::endl;
//          return;
//      }
//
//      // ...
//
//      session.stop();
//  }
//..
//
///Opening queues
///--------------
// Once the &#39;Session&#39; has been created and started, the application can use it
// to open queues for producing and/or consuming messages.  A queue is
// associated with a domain.  Domain metadata must be deployed in the BlazingMQ
// infrastructure prior to opening queues under that domain, because opening a
// queue actually loads the metadata deployed for the associated domain.
//
// The metadata associated with a domain defines various parameters like
// maximum queue size and capacity, persistent policy, routing policy, etc.
//
// Queue are identified by URIs (Unified Resource Identifiers) that must
// follow the BlazingMQsyntax, manipulated as &#39;bmqt::Uri&#39; objects.  A queue URI
// is typically formatted as follows:
//..
//  bmq://my.domain/my.queue
//..
// Note that domain names are unique in BlazingMQ infrastructure, which makes a
// fully qualified queue URI unique too.
//
// Queues in BlazingMQ infrastructure are created by applications on demand.
// Broke creates a queue when it receives an open-queue request from an
// application for a queue that does not exist currently.
//
// Application can open a queue by calling &#39;openQueue&#39; or &#39;openQueueAsync&#39;
// method on a started session.  Application must pass appropriate flags to
// indicate if it wants to post messages to queue, consume messages from the
// queue, or both.
//
// Note that &#39;openQueue&#39; is a blocking method, and returns after specified
// queue has been successfully opened (success) or after specified timeout has
// expired (failure).  &#39;openQueueAsync&#39; method, as the name suggests, is non
// blocking, and the result of the operation is notified via
// &#39;bmqt::SessionEventType::QUEUE_OPEN_RESULT&#39; session event.
//
///Example 4
///- - - - -
// The following example demonstrates how to open a queue for posting messages.
// The code first opens the queue with appropriate flags, and then uses
// &#39;bmqa::MessageEventBuilder&#39; to build a message event and post to the queue.
//..
//  // Session creation and startup logic elided for brevity
//  const char *queueUri = &quot;bmq://my.domain/my.queue&quot;;
//  bmqa::QueueId myQueueId(1);       // ID for the queue
//  int rc = session.openQueue(
//                      &amp;myQueueId,
//                      queueUri,
//                      bmqt::QueueFlags::e_WRITE | bmqt::QueueFlags::e_ACK,
//                      bsls::TimeInterval(30, 0));
//
//  if (rc != 0) {
//      bsl::cerr &lt;&lt; &quot;Failed to open queue, rc: &quot;
//                &lt;&lt; bmqt::OpenQueueResult::Enum(rc)
//                &lt;&lt; bsl::endl;
//      return;
//  }
//..
// Note that apart from &#39;WRITE&#39; flag, &#39;ACK&#39; flag has been passed to
// &#39;openQueue&#39; method above.  This indicates that application is interested in
// receiving &#39;ACK&#39; notification for each message it posts to the queue,
// irrespective of whether or not the message was successfully received by the
// broker and posted to the queue.
//
// Once the queue has been successfully opened for writing, messages can be
// posted to the queue for consumption by interested applications.  We will use
// &#39;bmqa::MessageEventBuilder&#39; to build a message event.
//..
//  // Create a message event builder
//  bmqa::MessageEventBuilder builder;
//  session.loadMessageEventBuilder(&amp;builder);
//
//  // Create and post a message event containing 1 message
//  bmqa::Message&amp; msg = builder.startMessage();
//
//  msg.setCorrelationId(myCorrelationId);
//  msg.setDataRef(&amp;myPayload);  // where &#39;myPayload&#39; is of type &#39;bdlbb::Blob&#39;
//  rc = builder.packMessage(myQueueId);
//  if (rc != 0) {
//      bsl::cerr &lt;&lt; &quot;Failed to pack message, rc: &quot;
//                &lt;&lt; bmqt::EventBuilderResult::Enum(rc)
//                &lt;&lt; bsl::endl;
//      return;
//  }
//
//  // Post message event
//  rc = session.post(builder.messageEvent());
//  if (rc != 0) {
//      bsl::cerr &lt;&lt; &quot;Failed to post message event to the queue, rc: &quot;
//                &lt;&lt; bmqt::PostResult::Enum(rc)
//                &lt;&lt; bsl::endl;
//      return;
//  }
//
//  // ... post more messages
//..
//
///Closing queues
///--------------
// After an application no longer needs to produce or consume messages from a
// queue, it can be closed by &#39;closeQueue&#39; or &#39;closeQueueAsync&#39; method.  Note
// that closing a queue closes an application&#39;s &quot;view&quot; on the queue, and may
// not lead to queue deletion in the broker.  A &#39;Session&#39; does not expose any
// method to explicitly delete a queue.
//
// Note that &#39;closeQueue&#39; is a blocking method and returns after the specified
// queue has been successfully closed (success) or after specified timeout has
// expired (failure).  &#39;closeQueueAsync&#39;, as the name suggests, is a
// non-blocking method, and result of the operation is notified via
// &#39;bmqt::SessionEventType::e_QUEUE_CLOSE_RESULT&#39; session event.
//
// There are 3 flavors which behave differently with regard to thread blocking
// and callback execution:
///----------------------------------------------------------------------------
//           |  openQueue        |  openQueueSync       |  openQueueAsync
//           |  configureQueue   |  configureQueueSync  |  configureQueueAsync
//           |  closeQueue       |  closeQueueSync      |  closeQueueAsync
//           | (deprecated Sync) | (Synchronous)        | (Asynchronous)
//-----------|-------------------|----------------------|----------------------
//   event   | unblocks in       | unblocks in event    | executes callback in
//  handler  | internal thread   | handler thread  (*)  | event handler thread
//           |                   |                      |
// nextEvent | unblocks in       | unblocks in          | executes callback
//           | internal thread   | internal thread      | in nextEvent thread
//-----------------------------------------------------------------------------
//
// (*) - guarantees unblocking after all previously enqueued events have been
// emitted to the eventHandler, allowing the user to have proper serialization
// of events for the given queue (for example no more PUSH messages will be
// delivered through the eventHandler for the queue after
// configureQueueSync(maxUnconfirmed = 0) returns).

// BMQ
#include &lt;bmqscm_version.h&gt;
#include &lt;bmqa_abstractsession.h&gt;
#include &lt;bmqa_closequeuestatus.h&gt;
#include &lt;bmqa_configurequeuestatus.h&gt;
#include &lt;bmqa_confirmeventbuilder.h&gt;
#include &lt;bmqa_messageeventbuilder.h&gt;
#include &lt;bmqa_openqueuestatus.h&gt;
#include &lt;bmqt_queueoptions.h&gt;
#include &lt;bmqt_sessionoptions.h&gt;
#include &lt;bmqt_uri.h&gt;

// BDE
#include &lt;ball_log.h&gt;
#include &lt;bsl_memory.h&gt;
#include &lt;bsl_string.h&gt;
#include &lt;bslma_allocator.h&gt;
#include &lt;bslma_managedptr.h&gt;
#include &lt;bslma_usesbslmaallocator.h&gt;
#include &lt;bslmf_nestedtraitdeclaration.h&gt;
#include &lt;bsls_keyword.h&gt;
#include &lt;bsls_timeinterval.h&gt;
#include &lt;bsls_types.h&gt;


namespace BloombergLP {

// FORWARD DECLARATION
namespace bmqimp { class Application; }
namespace bmqimp { class Event; }
namespace bmqp   { class MessageGUIDGenerator; }
namespace bslmt  { class Semaphore; }

namespace bmqa {

// FORWARD DECLARATION
class Event;
class Message;
class MessageEvent;
class MessageProperties;
class QueueId;
class SessionEvent;


                         // =========================
                         // class SessionEventHandler
                         // =========================

class SessionEventHandler {
    // Pure protocol for an asynchronous event handler.  The implementation
    // must be thread safe if the &#39;Session&#39; is configured to use multiple
    // threads.

  public:
    // CREATORS
    virtual
    ~SessionEventHandler();
        // Destroy this object.

    // MANIPULATORS
    virtual
    void onSessionEvent(const SessionEvent&amp; event) = 0;
        // Process the specified session &#39;event&#39; (connected, disconnected,
        // queue opened, queue closed, etc.).

    virtual
    void onMessageEvent(const MessageEvent&amp; event) = 0;
        // Process the specified message &#39;event&#39; containing one or more
        // messages.
};


                             // ==================
                             // struct SessionImpl
                             // ==================

struct SessionImpl {
    // Impl structure for the session data members, so that special task such
    // as &#39;bmqadm&#39; can access them by reinterpret casting a &#39;Session&#39; object.
    // Care should be taken though since &#39;Session&#39; is a polymorphic class.

    // PUBLIC DATA
    bslma::Allocator                       *d_allocator_p;
                                             // The allocator to use

    bmqt::SessionOptions                    d_sessionOptions;
                                             // Session options as provided by
                                             // the application.

    bslma::ManagedPtr&lt;SessionEventHandler&gt;  d_eventHandler_mp;
                                             // Event handler, if any, to use
                                             // for notifying application of
                                             // events.

    bsl::shared_ptr&lt;bmqp::MessageGUIDGenerator&gt;
                                            d_guidGenerator_sp;
                                             // GUID generator object.

    bslma::ManagedPtr&lt;bmqimp::Application&gt;  d_application_mp;
                                             // The application object.

  private:
    // NOT IMPLEMENTED
    SessionImpl(const SessionImpl&amp;)            BSLS_KEYWORD_DELETED;
    SessionImpl&amp; operator=(const SessionImpl&amp;) BSLS_KEYWORD_DELETED;

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION(SessionImpl, bslma::UsesBslmaAllocator)

    // CREATORS
    SessionImpl(const bmqt::SessionOptions&amp;             options,
                bslma::ManagedPtr&lt;SessionEventHandler&gt;  eventHandler,
                bslma::Allocator                       *allocator = 0);
        // Create a new object having the specified &#39;options&#39; and
        // &#39;eventHandler&#39; and using the optionally specified &#39;allocator&#39;.
};


                               // =============
                               // class Session
                               // =============

class Session: public AbstractSession {
    // A session with a BlazingMQ broker.

  public:
    // TYPES
    typedef AbstractSession::OpenQueueCallback      OpenQueueCallback;
        // Invoked as a response to an asynchronous open queue operation,
        // &#39;OpenQueueCallback&#39; is an alias for a callback function object
        // (functor) that takes as an argument the specified &#39;result&#39;,
        // providing the result and context of the requested operation.

    typedef AbstractSession::ConfigureQueueCallback ConfigureQueueCallback;
        // Invoked as a response to an asynchronous configure queue operation,
        // &#39;ConfigureQueueCallback&#39; is an alias for a callback function object
        // (functor) that takes as an argument the specified &#39;result&#39;,
        // providing the result and context of the requested operation.

    typedef AbstractSession::CloseQueueCallback     CloseQueueCallback;
        // Invoked as a response to an asynchronous close queue operation,
        // &#39;CloseQueueCallback&#39; is an alias for a callback function object
        // (functor) that takes as an argument the specified &#39;result&#39;,
        // providing the result and context of the requested operation.

  private:
    // CLASS-SCOPE CATEGORY
    BALL_LOG_SET_CLASS_CATEGORY(&quot;BMQA.SESSION&quot;);

  private:
    // DATA
    SessionImpl d_impl; // Sole data member of this object.

  private:
    // NOT IMPLEMENTED
    Session(const Session&amp;)            BSLS_KEYWORD_DELETED;
    Session&amp; operator=(const Session&amp;) BSLS_KEYWORD_DELETED;
        // Copy constructor and assignment operator are not implemented

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION(Session, bslma::UsesBslmaAllocator)

    // CREATORS
    explicit
    Session(const bmqt::SessionOptions&amp;  options   = bmqt::SessionOptions(),
            bslma::Allocator            *allocator = 0);
        // Create a new &#39;Session&#39; in *synchronous* mode using the optionally
        // specified &#39;options&#39;.  In such mode, events have to be fetched by the
        // application using the &#39;nextEvent()&#39; method.  Optionally specify an
        // &#39;allocator&#39; used to supply memory.  If &#39;allocator&#39; is 0, the
        // currently installed default allocator is used.

    explicit
    Session(bslma::ManagedPtr&lt;SessionEventHandler&gt;  eventHandler,
            const bmqt::SessionOptions&amp;             options   =
                                                        bmqt::SessionOptions(),
            bslma::Allocator                       *allocator = 0);
        // Create a &#39;Session&#39; in *asynchronous* mode using the specified
        // &#39;eventHandler&#39; as callback for event processing and the optionally
        // specified &#39;options&#39;.  Optionally specify an &#39;allocator&#39; used to
        // supply memory.  If the optionally specified &#39;allocator&#39; is 0, the
        // currently installed default allocator is used.

    ~Session() BSLS_KEYWORD_OVERRIDE;
        // Stop the &#39;Session&#39; and destroy this object.

    // MANIPULATORS
    //   (virtual bmqa::AbstractSession)

    ///Session management
    ///------------------
    int start(const bsls::TimeInterval&amp; timeout = bsls::TimeInterval())
                                                         BSLS_KEYWORD_OVERRIDE;
        // Connect to the BlazingMQ broker and start the message processing for
        // this &#39;Session&#39;.  This method blocks until either the &#39;Session&#39; is
        // connected to the broker, fails to connect, or the operation times
        // out.  If the optionally specified &#39;timeout&#39; is not populated, use
        // the one defined in the session options.  Return 0 on success, or a
        // non-zero value corresponding to the &#39;bmqt::GenericResult::Enum&#39; enum
        // values otherwise.  The behavior is undefined if this method is
        // called on an already started &#39;Session&#39;.

    int startAsync(const bsls::TimeInterval&amp; timeout = bsls::TimeInterval())
                                                         BSLS_KEYWORD_OVERRIDE;
        // Connect to the BlazingMQ broker and start the message processing for
        // this &#39;Session&#39;.  This method returns without blocking.  The result
        // of the operation is communicated with a session event.  If the
        // optionally specified &#39;timeout&#39; is not populated, use the one defined
        // in the session options.  Return 0 on success (this doesn&#39;t imply the
        // session is connected !), or a non-zero value corresponding to the
        // &#39;bmqt::GenericResult::Enum&#39; enum values otherwise.  The behavior is
        // undefined if this method is called on an already started &#39;Session&#39;.

    void stop() BSLS_KEYWORD_OVERRIDE;
        // Gracefully disconnect from the BlazingMQ broker and stop the
        // operation of this &#39;Session&#39;.  This method blocks waiting for all
        // already invoked event handlers to exit and all session-related
        // operations to be finished.  No other method but &#39;start()&#39; may be
        // used after this method returns.  This method must *NOT* be called if
        // the session is in synchronous mode (i.e., not using the
        // EventHandler), &#39;stopAsync()&#39; should be called in this case.

    void stopAsync() BSLS_KEYWORD_OVERRIDE;
        // Disconnect from the BlazingMQ broker and stop the operation of this
        // &#39;Session&#39;.  This method returns without blocking and neither enforce
        // nor waits for any already started session-related operation to be
        // finished.  No method may be used after this method returns.

    void finalizeStop() BSLS_KEYWORD_OVERRIDE;
        // **DEPRECATED**
        //
        // This method is only to be used if the session is in synchronous mode
        // (i.e., not using the EventHandler): it must be called once all
        // threads getting events with &#39;nextEvent()&#39; have been joined.

    virtual
    MessageEventBuilder createMessageEventBuilder();
        // Return a MessageEventBuilder that can be used to build message event
        // for posting on this session.  The behavior is undefined unless the
        // session has been successfully started.  Note that lifetime of the
        // returned object is bound by the lifetime of this session instance
        // (i.e., returned instance cannot outlive this session instance).
        // Also note that the &#39;MessageEventBuilder&#39; objects are pooled, so this
        // operation is cheap, and &#39;MessageEventBuilder&#39; can be obtained on
        // demand and kept on the stack.
        //
        // DEPRECATED: Use the &#39;loadMessageEventBuilder instead.  This
        //             method will be marked as &#39;BSLS_ANNOTATION_DEPRECATED&#39; in
        //             future release of libbmq.

    void loadMessageEventBuilder(MessageEventBuilder *builder)
                                                         BSLS_KEYWORD_OVERRIDE;
        // Load into the specified &#39;builder&#39; an instance of
        // &#39;bmqa::MessageEventBuilder&#39; that can be used to build message event
        // for posting on this session.  The behavior is undefined unless the
        // session has been successfully started and &#39;builder&#39; is non-null.
        // Note that lifetime of the loaded object is bound by the lifetime of
        // this session instance (i.e., loaded instance cannot outlive this
        // session instance).  Also note that the &#39;MessageEventBuilder&#39; objects
        // are pooled, so this operation is cheap, and &#39;MessageEventBuilder&#39;
        // can be obtained on demand and kept on the stack.

    void loadConfirmEventBuilder(ConfirmEventBuilder *builder)
                                                         BSLS_KEYWORD_OVERRIDE;
        // Load into the specified &#39;builder&#39; an instance of
        // &#39;bmqa::ConfirmEventBuilder&#39; that can be used to build a batch of
        // CONFIRM messages for sending to the broker.  The behavior is
        // undefined unless the session has been successfully started and
        // &#39;builder&#39; is non-null.  Note that the lifetime of the loaded object
        // is bound by the lifetime of this session instance (i.e., loaded
        // instance cannot outlive this session instance).

    void loadMessageProperties(MessageProperties *buffer)
                                                         BSLS_KEYWORD_OVERRIDE;
        // Load into the specified &#39;buffer&#39; an instance of &#39;MessageProperties&#39;
        // that can be used to specify and associate properties while building
        // a &#39;bmqa::Message&#39;.  The behavior is undefined unless the session has
        // been successfully started and &#39;buffer&#39; is non-null.  Note that
        // lifetime of the loaded object is bound by the lifetime of this
        // session instance (i.e., loaded instance cannot outlive this session
        // instance).

    ///Queue management
    ///----------------
    int getQueueId(QueueId          *queueId,
                   const bmqt::Uri&amp;  uri) const BSLS_KEYWORD_OVERRIDE;
        // Load in the specified &#39;queueId&#39; the queue corresponding to the
        // specified &#39;uri&#39; and return 0 if such a queue was found, or leave
        // &#39;queueId&#39; untouched and return a non-zero value if no queue
        // corresponding to &#39;uri&#39; is currently open.

    int getQueueId(QueueId                    *queueId,
                   const bmqt::CorrelationId&amp;  correlationId) const
                                                         BSLS_KEYWORD_OVERRIDE;
        // Load in the specified &#39;queueId&#39; the queue corresponding to the
        // specified &#39;correlationId&#39; and return 0 if such a queue was found, or
        // leave &#39;queueId&#39; untouched and return a non-zero value if no queue
        // corresponding to &#39;correlationId&#39; is currently open.

    int openQueue(QueueId                   *queueId,
                  const bmqt::Uri&amp;           uri,
                  bsls::Types::Uint64        flags,
                  const bmqt::QueueOptions&amp;  options = bmqt::QueueOptions(),
                  const bsls::TimeInterval&amp;  timeout = bsls::TimeInterval())
                                                         BSLS_KEYWORD_OVERRIDE;
        // DEPRECATED: Use the &#39;openQueueSync(QueueId *queueId...)&#39; instead.
        //             This method will be marked as
        //             &#39;BSLS_ANNOTATION_DEPRECATED&#39; in future release of
        //             libbmq.

    OpenQueueStatus
    openQueueSync(QueueId                   *queueId,
                  const bmqt::Uri&amp;           uri,
                  bsls::Types::Uint64        flags,
                  const bmqt::QueueOptions&amp;  options = bmqt::QueueOptions(),
                  const bsls::TimeInterval&amp;  timeout = bsls::TimeInterval())
                                                         BSLS_KEYWORD_OVERRIDE;
        // Open the queue having the specified &#39;uri&#39; with the specified &#39;flags&#39;
        // (a combination of the values defined in &#39;bmqt::QueueFlags::Enum&#39;),
        // using the specified &#39;queueId&#39; to correlate events related to that
        // queue.  The object &#39;queueId&#39; referring to is modified, so the
        // &#39;queueId&#39; represents the actual queue uri, flags and options.
        // Return a result providing the status and context of the operation.
        // Use the optionally specified &#39;options&#39; to configure some advanced
        // settings.  Note that this operation fails if &#39;queueId&#39; is
        // non-unique.  If the optionally specified &#39;timeout&#39; is not populated,
        // use the one defined in the session options.  This operation will
        // block until either success, failure, or timing out happens.
        //
        // THREAD: Note that calling this method from the event processing
        //         thread(s) (i.e., from the EventHandler callback, if
        //         provided) *WILL* lead to a *DEADLOCK*.

    virtual
    int openQueue(const QueueId&amp;            queueId,
                  const bmqt::Uri&amp;          uri,
                  bsls::Types::Uint64       flags,
                  const bmqt::QueueOptions&amp; options = bmqt::QueueOptions(),
                  const bsls::TimeInterval&amp; timeout = bsls::TimeInterval());
        // DEPRECATED: Use the &#39;openQueue(QueueId *queueId...)&#39; instead.  This
        //             method will be marked as &#39;BSLS_ANNOTATION_DEPRECATED&#39; in
        //             future release of libbmq.

    int
    openQueueAsync(QueueId                   *queueId,
                   const bmqt::Uri&amp;           uri,
                   bsls::Types::Uint64        flags,
                   const bmqt::QueueOptions&amp;  options = bmqt::QueueOptions(),
                   const bsls::TimeInterval&amp;  timeout = bsls::TimeInterval())
                                                         BSLS_KEYWORD_OVERRIDE;
        // DEPRECATED: Use the &#39;openQueueAsync(...)&#39; with callback flavor
        //             instead.  This method will be marked as
        //             &#39;BSLS_ANNOTATION_DEPRECATED&#39; in future release of
        //             libbmq.

    void
    openQueueAsync(QueueId                   *queueId,
                   const bmqt::Uri&amp;           uri,
                   bsls::Types::Uint64        flags,
                   const OpenQueueCallback&amp;   callback,
                   const bmqt::QueueOptions&amp;  options  = bmqt::QueueOptions(),
                   const bsls::TimeInterval&amp;  timeout  = bsls::TimeInterval())
                                                         BSLS_KEYWORD_OVERRIDE;
        // Asynchronously open the queue having the specified &#39;uri&#39; with the
        // specified &#39;flags&#39; (a combination of the values defined in
        // &#39;bmqt::QueueFlags::Enum&#39;), using the specified &#39;queueId&#39; to
        // correlate events related to that queue and the optionally specified
        // &#39;options&#39; to configure some advanced settings.  The object &#39;queueId&#39;
        // referring to is modified, so the &#39;queueId&#39; represents the actual
        // queue uri, flags and options.  The result of the operation is
        // communicated to the specified &#39;callback&#39; via a
        // &#39;bmqa::OpenQueueStatus&#39;, providing the status and context of the
        // requested operation.  Note that this operation fails if &#39;queueId&#39; is
        // non-unique.  If the optionally specified &#39;timeout&#39; is not populated,
        // use the one defined in the session options.
        //
        // THREAD: The &#39;callback&#39; will *ALWAYS* be invoked from the
        //         EventHandler thread(s) (or if a SessionEventHandler was not
        //         specified, from the thread invoking &#39;nextEvent&#39;).

    int
    configureQueue(QueueId                   *queueId,
                   const bmqt::QueueOptions&amp;  options,
                   const bsls::TimeInterval&amp;  timeout = bsls::TimeInterval())
                                                         BSLS_KEYWORD_OVERRIDE;
        // DEPRECATED: Use the &#39;configureQueueSync(QueueId *queueId...)
        //             instead.  This method will be marked as
        //             &#39;BSLS_ANNOTATION_DEPRECATED&#39; in future release of
        //             libbmq.

    ConfigureQueueStatus
    configureQueueSync(
                    const QueueId             *queueId,
                    const bmqt::QueueOptions&amp;  options,
                    const bsls::TimeInterval&amp;  timeout = bsls::TimeInterval())
                                                         BSLS_KEYWORD_OVERRIDE;
        // Configure the queue identified by the specified &#39;queueId&#39; using the
        // specified &#39;options&#39; and return a result providing the status and
        // context of the operation.  If the optionally specified &#39;timeout&#39; is
        // not populated, use the one defined in the session options.  This
        // operation returns error if there is a pending configure for the same
        // queue.  This operation will block until either success, failure, or
        // timing out happens.
        //
        // Note that the following &#39;bmqt::QueueOptions&#39; fields cannot be
        // reconfigured after the queue has been opened:
        //   - suspendsOnBadHostHealth
        // Attempts to reconfigure these fields will yield an &#39;e_NOT_SUPPORTED&#39;
        // error code.
        //
        // THREAD: Note that calling this method from the event processing
        //         thread(s) (i.e., from the EventHandler callback, if
        //         provided) *WILL* lead to a *DEADLOCK*.

    int configureQueueAsync(
                    QueueId                   *queueId,
                    const bmqt::QueueOptions&amp;  options,
                    const bsls::TimeInterval&amp;  timeout = bsls::TimeInterval())
                                                         BSLS_KEYWORD_OVERRIDE;
        // DEPRECATED: Use the &#39;configureQueueAsync(...)&#39; with callback flavor
        //             instead.  This method will be marked as
        //             &#39;BSLS_ANNOTATION_DEPRECATED&#39; in future release of
        //             libbmq.

    void configureQueueAsync(
               const QueueId                 *queueId,
               const bmqt::QueueOptions&amp;      options,
               const ConfigureQueueCallback&amp;  callback,
               const bsls::TimeInterval&amp;      timeout  = bsls::TimeInterval())
                                                         BSLS_KEYWORD_OVERRIDE;
        // Asynchronously configure the queue identified by the specified
        // &#39;queueId&#39; using the specified &#39;options&#39; to configure some advanced
        // settings.  The result of the operation is communicated to the
        // specified &#39;callback&#39; via a &#39;bmqa::ConfigureQueueStatus&#39;, providing
        // the status and context of the requested operation.  If the
        // optionally specified &#39;timeout&#39; is not populated, use the one defined
        // in the session options.
        //
        // Note that the following &#39;bmqt::QueueOptions&#39; fields cannot be
        // reconfigured after the queue has been opened:
        //   - suspendsOnBadHostHealth
        // Attempts to reconfigure these fields will yield an &#39;e_NOT_SUPPORTED&#39;
        // error code.
        //
        // THREAD: The &#39;callback&#39; will *ALWAYS* be invoked from the
        //         EventHandler thread(s) (or if a SessionEventHandler was not
        //         specified, from the thread invoking &#39;nextEvent&#39;).

    int closeQueue(QueueId                   *queueId,
                   const bsls::TimeInterval&amp;  timeout = bsls::TimeInterval())
                                                         BSLS_KEYWORD_OVERRIDE;
        // DEPRECATED: Use the &#39;closeQueueSync(QueueId *queueId...) instead.
        //             This method will be marked as
        //             &#39;BSLS_ANNOTATION_DEPRECATED&#39; in future release of
        //             libbmq.

    CloseQueueStatus
    closeQueueSync(const QueueId             *queueId,
                   const bsls::TimeInterval&amp;  timeout = bsls::TimeInterval())
                                                         BSLS_KEYWORD_OVERRIDE;
        // Close the queue identified by the specified &#39;queueId&#39; and return a
        // result providing the status and context of the operation.  If the
        // optionally specified &#39;timeout&#39; is not populated, use the one defined
        // in the session options.  Any outstanding configureQueue request for
        // this &#39;queueId&#39; will be canceled.  This operation will block until
        // either success, failure, or timing out happens.  Once this method
        // returns, there is guarantee that no more messages and events for
        // this &#39;queueId&#39; will be received.  Note that successful processing of
        // this request in the broker closes this session&#39;s view of the queue;
        // the underlying queue may not be deleted in the broker.  When this
        // method returns, the correlationId associated to the queue is
        // cleared.
        //
        // THREAD: Note that calling this method from the event processing
        //         thread(s) (i.e., from the EventHandler callback, if
        //         provided) *WILL* lead to a *DEADLOCK*.

    virtual
    int closeQueue(const QueueId&amp;            queueId,
                   const bsls::TimeInterval&amp; timeout = bsls::TimeInterval());
        // DEPRECATED: Use the &#39;closeQueue(QueueId *queueId...) instead.  This
        //             method will be marked as &#39;BSLS_ANNOTATION_DEPRECATED&#39; in
        //             future release of libbmq.

    int
    closeQueueAsync(QueueId                   *queueId,
                    const bsls::TimeInterval&amp;  timeout = bsls::TimeInterval())
                                                         BSLS_KEYWORD_OVERRIDE;
        // DEPRECATED: Use the &#39;closeQueueAsync(...)&#39; with callback flavor
        //             instead.  This method will be marked as
        //             &#39;BSLS_ANNOTATION_DEPRECATED&#39; in future release of
        //             libbmq.

    void closeQueueAsync(
                   const QueueId             *queueId,
                   const CloseQueueCallback&amp;  callback,
                   const bsls::TimeInterval&amp;  timeout  = bsls::TimeInterval())
                                                         BSLS_KEYWORD_OVERRIDE;
        // Asynchronously close the queue identified by the specified
        // &#39;queueId&#39;.  Any outstanding configureQueue requests will be
        // canceled.  The result of the operation is communicated to the
        // specified &#39;callback&#39; via a &#39;bmqa::CloseQueueStatus&#39;, providing the
        // status and context of the operation.  If the optionally specified
        // &#39;timeout&#39; is not populated, use the one defined in the session
        // options.  Note that successful processing of this request in the
        // broker closes this session&#39;s view of the queue; the underlying queue
        // may not be deleted in the broker.  The correlationId associated to
        // the queue remains valid until the &#39;bmqa::CloseQueueStatus&#39; result
        // has been received and processed by the &#39;callback&#39;, after which it
        // will be cleared and no more messages and events for this &#39;queueId&#39;
        // will be received.
        //
        // THREAD: The &#39;callback&#39; will *ALWAYS* be invoked from the
        //         EventHandler thread(s) (or if a SessionEventHandler was not
        //         specified, from the thread invoking &#39;nextEvent&#39;).

    virtual
    int
    closeQueueAsync(const QueueId&amp;            queueId,
                    const bsls::TimeInterval&amp; timeout = bsls::TimeInterval());
        // DEPRECATED: Use the &#39;closeQueueAsync(...)&#39; with callback flavor
        //             instead.  This method will be marked as
        //             &#39;BSLS_ANNOTATION_DEPRECATED&#39; in future release of
        //             libbmq.

    ///Queue manipulation
    ///------------------
    Event nextEvent(const bsls::TimeInterval&amp; timeout = bsls::TimeInterval())
                                                         BSLS_KEYWORD_OVERRIDE;
        // Return the next available event received for this session.  If there
        // is no event available, this method blocks for up to the optionally
        // specified &#39;timeout&#39; time interval for an event to arrive.  An empty
        // time interval for &#39;timeout&#39; (the default) indicates that the method
        // should not timeout (the method will not return until the next event
        // is available).  Return a &#39;bmqa::SessionEvent&#39; of type
        // &#39;bmqt::SessionEventType::e_TIMEOUT&#39; if a timeout was specified and
        // that timeout expired before any event was received.  Note that this
        // method can only be used if the session is in synchronous mode (ie
        // not using the EventHandler).  The behavior is undefined unless the
        // session was started.

    int post(const MessageEvent&amp; event) BSLS_KEYWORD_OVERRIDE;
        // Asynchronously post the specified &#39;event&#39; that must contain one or
        // more &#39;Messages&#39;.  The return value is one of the values defined in
        // the &#39;bmqt::PostResult::Enum&#39; enum.  Return zero on success and a
        // non-zero value otherwise.  Note that success implies that SDK has
        // accepted the &#39;event&#39; and will eventually deliver it to the broker.
        // The behavior is undefined unless the session was started.

    int confirmMessage(const Message&amp; message) BSLS_KEYWORD_OVERRIDE;
        // Asynchronously confirm the receipt of the specified &#39;message&#39;.  This
        // indicates that the application is done processing the message and
        // that the broker can safely discard it from the queue according to
        // the retention policy set up for that queue.  Return 0 on success,
        // and a non-zero value otherwise.  Note that success implies that SDK
        // has accepted the &#39;message&#39; and will eventually send confirmation
        // notification to the broker.

    int confirmMessage(const MessageConfirmationCookie&amp; cookie)
                                                         BSLS_KEYWORD_OVERRIDE;
        // Asynchronously confirm the receipt of the message with which the
        // specified &#39;cookie&#39; is associated.  This indicates that the
        // application is done processing the message and that the broker can
        // safely discard it from the queue according to the retention policy
        // set up for that queue.  Return 0 on success, and a non-zero value
        // otherwise.  Note that success implies that SDK has accepted the
        // &#39;message&#39; and will eventually send confirmation notification to the
        // broker.

    int confirmMessages(ConfirmEventBuilder *builder) BSLS_KEYWORD_OVERRIDE;
        // Asynchronously confirm the receipt of the batch of CONFIRM messages
        // contained in the specified &#39;builder&#39;.  This indicates that the
        // application is done processing all of the messages and that the
        // broker can safely discard them from the queue according to the
        // retention policy set up for that queue.  The return value is one of
        // the values defined in the &#39;bmqt::GenericResult::Enum&#39; enum.  Note
        // that in case of success, the instance pointed by the &#39;builder&#39; will
        // be reset.  Also note that success implies that SDK has accepted all
        // of the messages in &#39;builder&#39; and will eventually send confirmation
        // notification to the broker, whereas failure implies that none of the
        // messages in &#39;builder&#39; were accepted.  Behavior is undefined unless
        // &#39;builder&#39; is non-null.

    ///Debugging related
    ///-----------------
    int configureMessageDumping(const bslstl::StringRef&amp; command)
                                                         BSLS_KEYWORD_OVERRIDE;
        // Configure this session instance to dump messages to the installed
        // logger at &#39;ball::Severity::INFO&#39; level according to the specified
        // &#39;command&#39; that should adhere to the following pattern:
        //..
        //   IN|OUT|PUSH|ACK|PUT|CONFIRM ON|OFF|100|10s
        //..
        // where each token has a specific meaning:
        //: o !IN!      : incoming (&#39;PUSH&#39; and &#39;ACK&#39;) events
        //: o !OUT!     : outgoing (&#39;PUT&#39; and &#39;CONFIRM&#39;) events
        //: o !PUSH!    : incoming &#39;PUSH&#39; events
        //: o !ACK!     : incoming &#39;ACK&#39; events
        //: o !PUT!     : outgoing &#39;PUT&#39; events
        //: o !CONFIRM! : outgoing &#39;CONFIRM&#39; events
        //: o !ON!      : turn on message dumping until explicitly turned off
        //: o !OFF!     : turn off message dumping
        //: o !100!     : turn on message dumping for the next 100 messages
        //: o !10s!     : turn on message dumping for the next 10 seconds
        // Above, the numerical values &#39;100&#39; and &#39;10&#39; are just for illustration
        // purposes, and application can choose an appropriate positive numeric
        // value for them.  Also, pattern is case-insensitive.  Return zero if
        // &#39;command&#39; is valid and message dumping has been configured, non-zero
        // value otherwise.  The behavior is undefined unless the session has
        // been started.

    ///Internal
    ///--------
    void *impl();
        // Do *NOT* use.  Internal function, reserved for BlazingMQ internal
        // usage.
};

// ============================================================================
//                             INLINE DEFINITIONS
// ============================================================================

                               // -------------
                               // class Session
                               // -------------

inline
int
Session::confirmMessage(const Message&amp; message)
{
    return confirmMessage(message.confirmationCookie());
}

inline
void*
Session::impl()
{
    return &amp;d_impl;
}


}  // close package namespace
}  // close enterprise namespace

#endif
</pre>
</body>
</html>
